#include <iostream>
#include <Windows.h>

//进度条
class ProgressBar {
private:
	HANDLE consoleHandle{ GetStdHandle(STD_OUTPUT_HANDLE) };	//控制台句柄
	CONSOLE_SCREEN_BUFFER_INFO consoleInfo{};	//控制台信息接参刷新使用 (非线程安全)
	SHORT positionY{ 0 };	//进度条在控制台锁定的行
	SHORT lastWidth{ 0 };	//进度条最后输出的宽度
	const int GRID_RATE{ 5 }; //一格代表的进度值
	int total{}; //总格数

	void init(SHORT y)
	{
		total = 100 / GRID_RATE;
		if ((100 % GRID_RATE) > 0)
		{
			total++;
		}
	}

public:
	ProgressBar() {
		//获取当前行作为进度条输出
		GetConsoleScreenBufferInfo(consoleHandle, &consoleInfo);
		COORD cursorPosition = consoleInfo.dwCursorPosition;
		init(cursorPosition.Y);
		//自动下一行 避免把后面的输出覆盖
		std::cout << std::endl;
	}

	ProgressBar(SHORT y) {
		init(y);
	}

	void show(int value) {
		//获取当前行在输出完成后 光标返回到之前的位置
		GetConsoleScreenBufferInfo(consoleHandle, &consoleInfo);
		COORD prePosition = consoleInfo.dwCursorPosition;

		//光条跳到进度条所在行 默认从x=0列开始输出
		SetConsoleCursorPosition(consoleHandle, COORD{ 0, positionY });
		//计算输出的各种符号数量
		if (value > 100) {
			value = 100;
		}
		if (value < 0) {
			value = 0;
		}
		int gridNum = value / GRID_RATE;	//所需要输出的格数
		int remainder = value % GRID_RATE;	//格数之后是否有余数
		int undone = remainder > 0 ? total - gridNum - 1 : total - gridNum;
		//控制台输出进度条
		std::cout << "┠";
		for (size_t i = 0; i < gridNum; i++)
		{
			std::cout << "█";
		}
		if (remainder > 0)
		{
			std::cout << "▌";
		}
		for (size_t i = 0; i < undone; i++)
		{
			std::cout << "  ";
		}
		std::cout << "┨" << value << "%";

		//覆盖之前的输出内容
		GetConsoleScreenBufferInfo(consoleHandle, &consoleInfo);
		COORD nowPosition = consoleInfo.dwCursorPosition;
		SHORT nowWidth = nowPosition.X;
		if (nowWidth < lastWidth)
		{
			for (size_t i = 0; i < lastWidth - nowWidth; i++)
			{
				std::cout << " ";
			}
		}
		//设置最新宽度
		lastWidth = nowWidth;
		//光标返回进入前的位置
		SetConsoleCursorPosition(consoleHandle, prePosition);
	}
};

int main()
{
	ProgressBar progress{};
	for (size_t i = 1; i <=100; i++)
	{
		Sleep(500);
		progress.show(i);

		std::cout << i << ",";
		if (i%10==0)
		{
			std::cout << std::endl;
		}
	}
	std::cout << "done!" << std::endl;
	return 0;
}